import json
import socketserver, os, sqlite3
import config
from database import User_DB


class MySocketServer(socketserver.BaseRequestHandler):
    def set_default(self):
        """
        设置服务器文件路径
        :return:
        """
        self.server_base_url = os.getcwd() + "\\server\\"

    def put(self, *args):
        """
        服务端接收文件长传请求
        :param args:
        :return:
        """
        command = args[0]
        client_file_path = command['filepath']
        client_filename = client_file_path.split("\\")[-1]
        client_file_size = command['size']
        exists_in_server = os.path.isfile(self.server_base_url + client_filename)
        recieved_size = 0
        if exists_in_server:
            exists_filesize = os.path.getsize(self.server_base_url+client_filename)
            # 服务端告知客户端文件传输开始的位置
            respon_info = f"start at {exists_filesize}".encode("utf-8")
            if exists_filesize == client_file_size:
                print("-----文件已存在，生成备份文件-----")
                respon_info = f"start at {0}".encode("utf-8")
                file = open(self.server_base_url + "_" + client_filename, "wb")
            else:
                print("-----断点续传-----")
                recieved_size = exists_filesize
                file = open(self.server_base_url+client_filename, "ab")
        else:
            respon_info = f"start at {0}".encode("utf-8")
            file = open(self.server_base_url + client_filename, "wb")
        self.request.send(respon_info)
        print(f"-----client {self.client_address} starts upload-----")

        while recieved_size < client_file_size:
            # 一次一次的接收，防止粘包
            # 客户端传输文件大小的作用在这里就能体现出来了，是为了判断文件什么时候能传输完
            data = self.request.recv(1024)
            file.write(data)
            recieved_size += len(data)
        print("-----file transportation done-----")
        file.close()

    def get(self, *args):
        """
        客户端下载文件
        :param args:
        :return:
        """
        fileInfo = {
            "filepath": "",
            "filesize": "",
            "action": "get",
            "file_exists": ""
        }
        command = args[0]
        file_abs_path = command["filepath"]
        file_exists = os.path.isfile(file_abs_path)
        if file_exists:
            filesize = os.stat(file_abs_path).st_size
            fileInfo["filepath"] = file_abs_path
            fileInfo["filesize"] = filesize
            fileInfo["file_exists"] = file_exists
            self.request.send(json.dumps(fileInfo).encode("utf-8"))
            # 等待客户端的确认信号，在这里阻塞服务端进程
            client_response = self.request.recv(1024)
            # 尝试找到应该开始传输的点
            try:
                start_pos = int(client_response.decode("utf-8").split()[-1])
            except Exception as e:
                print(f"-----can't find start position, {e}-----")
                return
            file = open(file_abs_path, "rb")
            if start_pos == 0:
                for line in file:
                    self.request.send(line)
            else:
                # 断点续传，使用seek方法
                with open(file_abs_path, 'rb') as f:
                    f.seek(start_pos)
                    while start_pos < filesize:
                        data = f.read(1024)
                        self.request.send(data)
                        start_pos += len(data)
            file.close()
        else:
            self.request.send(json.dumps(fileInfo).encode("utf-8"))

    def client_authentication(self):
        """
        接收来自客户端的登录信息，将验证结果发送给用户
        :return:
        """
        client_mess = self.request.recv(1024)
        client_login_info = json.loads(client_mess.decode("utf-8"))
        db = User_DB()
        a = client_login_info["user_name"]
        query_text = "SELECT * FROM user_info WHERE user_name = '" + client_login_info["user_name"] + "';"
        query_res = db.exeQuery(query_text)
        for row in query_res:
            if row[-1] == client_login_info["cryp"]:
                self.request.send(b'1')
                # 用户确认登陆成功
                self.request.recv(1024)
                return True
        self.request.send(b'0')
        return False

    def handle(self) -> None:
        """
        服务端入口
        :return:
        """
        self.set_default()
        success = self.client_authentication()
        if success:
            while True:
                try:
                    data = self.request.recv(1024).strip()
                    if len(data) == 0:
                        continue
                    command = json.loads(data.decode('utf-8'))
                    action = command['action']
                    if hasattr(self, action):
                        func = getattr(self, action)
                        func(command)
                except Exception as e:
                    print(f"-----server went wrong, {e} -----")
        else:
            print("-----wrong user name or password-----")


if __name__ == '__main__':
    client, port = config.get_server_ip(), config.get_server_port()
    server = socketserver.ThreadingTCPServer((client, port), MySocketServer)
    server.serve_forever()
